package com.demo.function.thread.tomcat;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.threads.Constants;
import org.apache.tomcat.util.threads.TaskQueue;
import org.apache.tomcat.util.threads.TaskThreadFactory;
import org.apache.tomcat.util.threads.ThreadPoolExecutor;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * 测试使用tomcat线程池
 */
@Slf4j
public class TomcatThreadPool {

    /**
     * 测试线程池在并发任务处理时，优先使用最大线线程数的线程，当最大线程数满了之后再把多出来的任务放入队列
     * @throws InterruptedException 中断异常
     */
    public void execute() throws InterruptedException {
        ThreadPoolExecutor executor = init();
        for (int i = 0; i < 300; i++) {
            TestRunnable testRunnable = new TestRunnable(i);
            executor.execute(testRunnable);
        }

        for (int i = 0; i < 20; i++) {
            log.info("线程池信息：{}", executor);
            TimeUnit.SECONDS.sleep(1L);
        }
    }

    /**
     * 测试submit方法，是否优先使用最大线程数
     * @throws InterruptedException 中断异常
     * @throws ExecutionException 异常
     */
    public void submit() throws InterruptedException, ExecutionException {
        List<Future<Integer>> list = new ArrayList<>();
        ThreadPoolExecutor executor = init();
        for (int i = 0; i < 300; i++) {
            TestCallable testCallable = new TestCallable(i);
            Future<Integer> future = executor.submit(testCallable);
            list.add(future);
        }

        for (int i = 0; i < 20; i++) {
            log.info("线程池信息：{}", executor);
            TimeUnit.SECONDS.sleep(1L);
        }

        for (Future<Integer> future : list) {
            log.info("future = " + future.get());
        }
    }

    private ThreadPoolExecutor init() {
        TaskQueue taskqueue = new TaskQueue(Integer.MAX_VALUE);
        TaskThreadFactory tf = new TaskThreadFactory("tomcatThreadPool-", false, Thread.NORM_PRIORITY);
        ThreadPoolExecutor executor = new ThreadPoolExecutor(25, 200, 6000, TimeUnit.MILLISECONDS,taskqueue, tf);
        executor.setThreadRenewalDelay(Constants.DEFAULT_THREAD_RENEWAL_DELAY);
        taskqueue.setParent(executor);
        return executor;
    }

    @Slf4j
    @AllArgsConstructor
    private static class TestRunnable implements Runnable {

        private int i;
        @Override
        public void run() {
            log.info("i=" + i);
            try {
                TimeUnit.SECONDS.sleep(3L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Slf4j
    @AllArgsConstructor
    private static class TestCallable implements Callable<Integer> {

        private int i;
        @Override
        public Integer call() throws Exception {
            log.info("i = " + i);
            TimeUnit.SECONDS.sleep(1L);
            return i;
        }
    }
}
